sm: refactor mitm service handle acquisition

This commit is contained in:
Michael Scire 2019-06-20 02:21:01 -07:00
parent cead8a36ea
commit 44725c8910
2 changed files with 69 additions and 49 deletions

View file

@ -227,18 +227,8 @@ bool Registration::HasMitm(u64 service) {
return target_service != NULL && target_service->mitm_pid != 0; return target_service != NULL && target_service->mitm_pid != 0;
} }
Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) { Result Registration::GetMitmServiceHandleImpl(Registration::Service *target_service, u64 pid, Handle *out) {
Registration::Service *target_service = GetService(service); /* Send command to query if we should mitm. */
if (target_service == NULL || ShouldInitDefer(service) || target_service->mitm_waiting_ack) {
/* Note: This defers the result until later. */
return ResultServiceFrameworkRequestDeferredByUser;
}
*out = 0;
Result rc;
if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) {
rc = svcConnectToPort(out, target_service->port_h);
} else {
IpcCommand c; IpcCommand c;
ipcInitialize(&c); ipcInitialize(&c);
struct { struct {
@ -249,8 +239,11 @@ Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
info->magic = SFCI_MAGIC; info->magic = SFCI_MAGIC;
info->cmd_id = 65000; info->cmd_id = 65000;
info->pid = pid; info->pid = pid;
rc = ipcDispatch(target_service->mitm_query_h); R_TRY(ipcDispatch(target_service->mitm_query_h));
if (R_SUCCEEDED(rc)) {
/* Parse response to see if we should mitm. */
bool should_mitm;
{
IpcParsedCommand r; IpcParsedCommand r;
ipcParse(&r); ipcParse(&r);
struct { struct {
@ -258,31 +251,56 @@ Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
u64 result; u64 result;
bool should_mitm; bool should_mitm;
} *resp = ((decltype(resp))r.Raw); } *resp = ((decltype(resp))r.Raw);
rc = resp->result;
if (R_SUCCEEDED(rc)) { R_TRY(resp->result);
if (resp->should_mitm) { should_mitm = resp->should_mitm;
rc = svcConnectToPort(&target_service->mitm_fwd_sess_h, target_service->port_h); }
if (R_SUCCEEDED(rc)) {
rc = svcConnectToPort(out, target_service->mitm_port_h); /* If we shouldn't mitm, give normal session. */
if (R_SUCCEEDED(rc)) { if (!should_mitm) {
target_service->mitm_waiting_ack_pid = pid; return svcConnectToPort(out, target_service->port_h);
target_service->mitm_waiting_ack = true; }
} else {
/* Create both handles. If the second fails, close the first to prevent leak. */
R_TRY(svcConnectToPort(&target_service->mitm_fwd_sess_h, target_service->port_h));
R_TRY_CLEANUP(svcConnectToPort(out, target_service->mitm_port_h), {
svcCloseHandle(target_service->mitm_fwd_sess_h); svcCloseHandle(target_service->mitm_fwd_sess_h);
target_service->mitm_fwd_sess_h = 0; target_service->mitm_fwd_sess_h = 0;
});
target_service->mitm_waiting_ack_pid = pid;
target_service->mitm_waiting_ack = true;
return ResultSuccess;
} }
Result Registration::GetServiceHandleImpl(Registration::Service *target_service, u64 pid, Handle *out) {
/* Clear handle output. */
*out = 0;
/* If not mitm'd or mitm service is requesting, get normal session. */
if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) {
return svcConnectToPort(out, target_service->port_h);
} }
} else {
rc = svcConnectToPort(out, target_service->port_h); /* We're mitm'd. */
if (R_FAILED(GetMitmServiceHandleImpl(target_service, pid, out))) {
/* If the Mitm service is dead, just give a normal session. */
return svcConnectToPort(out, target_service->port_h);
} }
return ResultSuccess;
} }
Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
Registration::Service *target_service = GetService(service);
if (target_service == NULL || ShouldInitDefer(service) || target_service->mitm_waiting_ack) {
/* Note: This defers the result until later. */
return ResultServiceFrameworkRequestDeferredByUser;
} }
if (R_FAILED(rc)) {
rc = svcConnectToPort(out, target_service->port_h); R_TRY_CATCH(GetServiceHandleImpl(target_service, pid, out)) {
}
}
/* Convert Kernel result to SM result. */ /* Convert Kernel result to SM result. */
R_TRY_CATCH(rc) {
R_CATCH(ResultKernelOutOfSessions) { R_CATCH(ResultKernelOutOfSessions) {
return ResultSmInsufficientSessions; return ResultSmInsufficientSessions;
} }

View file

@ -72,6 +72,8 @@ class Registration {
/* Service management. */ /* Service management. */
static bool HasService(u64 service); static bool HasService(u64 service);
static bool HasMitm(u64 service); static bool HasMitm(u64 service);
static Result GetMitmServiceHandleImpl(Registration::Service *service, u64 pid, Handle *out);
static Result GetServiceHandleImpl(Registration::Service *service, u64 pid, Handle *out);
static Result GetServiceHandle(u64 pid, u64 service, Handle *out); static Result GetServiceHandle(u64 pid, u64 service, Handle *out);
static Result GetServiceForPid(u64 pid, u64 service, Handle *out); static Result GetServiceForPid(u64 pid, u64 service, Handle *out);
static Result RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out); static Result RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out);