mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
Outline user<->secure page copying.
This commit is contained in:
parent
a01d2c92b2
commit
ff07451280
3 changed files with 99 additions and 1 deletions
|
@ -6,6 +6,7 @@
|
||||||
#include "smc_api.h"
|
#include "smc_api.h"
|
||||||
#include "smc_user.h"
|
#include "smc_user.h"
|
||||||
#include "se.h"
|
#include "se.h"
|
||||||
|
#include "userpage.h"
|
||||||
|
|
||||||
#define SMC_USER_HANDLERS 0x13
|
#define SMC_USER_HANDLERS 0x13
|
||||||
#define SMC_PRIV_HANDLERS 0x9
|
#define SMC_PRIV_HANDLERS 0x9
|
||||||
|
@ -225,6 +226,10 @@ uint32_t smc_check_status(smc_args_t *args) {
|
||||||
uint32_t smc_get_result(smc_args_t *) {
|
uint32_t smc_get_result(smc_args_t *) {
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
unsigned char result_buf[0x400];
|
unsigned char result_buf[0x400];
|
||||||
|
upage_ref_t page_ref;
|
||||||
|
|
||||||
|
void *user_address = (void *)args->X[2];
|
||||||
|
|
||||||
if (g_smc_callback_key == 0) {
|
if (g_smc_callback_key == 0) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +246,16 @@ uint32_t smc_get_result(smc_args_t *) {
|
||||||
args->X[1] = g_smc_callback(result_buf, args->X[3]);
|
args->X[1] = g_smc_callback(result_buf, args->X[3]);
|
||||||
g_smc_callback_key = 0;
|
g_smc_callback_key = 0;
|
||||||
|
|
||||||
/* TODO: Copy result from result_buf into output in args->X[2] */
|
/* Initialize page reference. */
|
||||||
|
if (upage_init(&page_ref, user_address) == 0) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy result output back to user. */
|
||||||
|
if (secure_copy_to_user(&page_ref, user_address, result_buf, (size_t)args->X[3]) == 0) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
62
exosphere/userpage.c
Normal file
62
exosphere/userpage.c
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "userpage.h"
|
||||||
|
|
||||||
|
uint64_t g_secure_page_user_address = NULL;
|
||||||
|
|
||||||
|
/* Create a user page reference for the desired address. */
|
||||||
|
/* Returns 1 on success, 0 on failure. */
|
||||||
|
int upage_init(upage_ref_t *upage, void *user_address) {
|
||||||
|
upage->user_page = get_page_for_address(user_address);
|
||||||
|
upage->secure_page = 0ULL;
|
||||||
|
|
||||||
|
if (g_secure_page_user_address != NULL) {
|
||||||
|
/* Different ASLR'd address indicate SPL was rebooted. Panic. */
|
||||||
|
if (g_secure_page_user_address != upage->user_page) {
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
upage->secure_page = SECURE_USER_PAGE_ADDR;
|
||||||
|
} else {
|
||||||
|
/* Official (weak) validation for SPL's ASLR'd address. */
|
||||||
|
if (upage->user_page >> 31) {
|
||||||
|
g_secure_page_user_address = upage->user_page;
|
||||||
|
/* TODO: Map this page into the MMU and invalidate the TLB. */
|
||||||
|
upage->secure_page = SECURE_USER_PAGE_ADDR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return upage->secure_page != 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int user_copy_to_secure(upage_ref_t *upage, void *secure_dst, void *user_src, size_t size) {
|
||||||
|
/* Fail if the page doesn't match. */
|
||||||
|
if (get_page_for_address(user_src) != upage->user_page) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if we go past the page boundary. */
|
||||||
|
if (size != 0 && get_page_for_address(user_src + size - 1) != upage->user_page) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *secure_src = (void *)(upage->secure_page + ((uint64_t)user_src - upage->user_page));
|
||||||
|
memcpy(secure_dst, secure_src, size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secure_copy_to_user(upage_ref_t *upage, void *user_dst, void *secure_src, size_t size) {
|
||||||
|
/* Fail if the page doesn't match. */
|
||||||
|
if (get_page_for_address(user_dst) != upage->user_page) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if we go past the page boundary. */
|
||||||
|
if (size != 0 && get_page_for_address(user_dst + size - 1) != upage->user_page) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *secure_dst = (void *)(upage->secure_page + ((uint64_t)user_dst - upage->user_page));
|
||||||
|
memcpy(secure_dst, secure_src, size);
|
||||||
|
return 1;
|
||||||
|
}
|
22
exosphere/userpage.h
Normal file
22
exosphere/userpage.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef EXOSPHERE_USERPAGE_H
|
||||||
|
#define EXOSPHERE_USERPAGE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define SECURE_USER_PAGE_ADDR (0x1F01F4000ULL)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t user_page;
|
||||||
|
uint64_t secure_page;
|
||||||
|
} upage_ref_t;
|
||||||
|
|
||||||
|
int upage_init(upage_ref_t *user_page, void *user_address);
|
||||||
|
|
||||||
|
void user_copy_to_secure(upage_ref_t *user_page, void *secure_dst, void *user_src, size_t size);
|
||||||
|
void secure_copy_to_user(upage_ref_t *user_page, void *user_dst, void *secure_src, size_t size);
|
||||||
|
|
||||||
|
static inline uint64_t get_page_for_address(void *address) {
|
||||||
|
return ((uint64_t)(address)) & 0xFFFFFFFFFFFFF000ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue