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;
}
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;
}
*out = 0;
Result rc;
if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) {
rc = svcConnectToPort(out, target_service->port_h);
} else {
Result Registration::GetMitmServiceHandleImpl(Registration::Service *target_service, u64 pid, Handle *out) {
/* Send command to query if we should mitm. */
IpcCommand c;
ipcInitialize(&c);
struct {
@ -249,8 +239,11 @@ Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
info->magic = SFCI_MAGIC;
info->cmd_id = 65000;
info->pid = pid;
rc = ipcDispatch(target_service->mitm_query_h);
if (R_SUCCEEDED(rc)) {
R_TRY(ipcDispatch(target_service->mitm_query_h));
/* Parse response to see if we should mitm. */
bool should_mitm;
{
IpcParsedCommand r;
ipcParse(&r);
struct {
@ -258,31 +251,56 @@ Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
u64 result;
bool should_mitm;
} *resp = ((decltype(resp))r.Raw);
rc = resp->result;
if (R_SUCCEEDED(rc)) {
if (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 (R_SUCCEEDED(rc)) {
target_service->mitm_waiting_ack_pid = pid;
target_service->mitm_waiting_ack = true;
} else {
R_TRY(resp->result);
should_mitm = resp->should_mitm;
}
/* If we shouldn't mitm, give normal session. */
if (!should_mitm) {
return svcConnectToPort(out, target_service->port_h);
}
/* 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);
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. */
R_TRY_CATCH(rc) {
R_CATCH(ResultKernelOutOfSessions) {
return ResultSmInsufficientSessions;
}

View file

@ -72,6 +72,8 @@ class Registration {
/* Service management. */
static bool HasService(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 GetServiceForPid(u64 pid, u64 service, Handle *out);
static Result RegisterServiceForPid(u64 pid, u64 service, u64 max_sessions, bool is_light, Handle *out);