Created
September 9, 2016 00:37
-
-
Save ktemkin/049755ede87c8af20b344b18cbb0c77f to your computer and use it in GitHub Desktop.
Tampoline E0->EL2 PoC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Stuck inside the Xen domain-setup code... | |
| */ | |
| static struct mmio_handler_ops poc_mmio_ops; | |
| static void memory_trampoline_demo(struct domain *d) | |
| { | |
| /* | |
| * Remove domain permissions for the guest-physical memory address | |
| * 0x12345000. This should cause a second-level translation fault if | |
| * that memory address is accessed. | |
| */ | |
| unmap_mmio_regions(d, _gfn(0x12345000), 4096, _mfn(0x12345000)); | |
| /* | |
| * Ask Xen to route any second-level faults to those addresses to us. | |
| * If you were writing the hypervisor, you'd provide a fast-path to | |
| * your handler interface here. | |
| */ | |
| register_mmio_handler(d, &poc_mmio_ops, 0x12345000, 4096, NULL); | |
| } | |
| /** | |
| * The target code up at EL2. Since I decided to abuse Xen's MMIO virtualization | |
| * to get Xen to route the trap to me, I get a bunch of additional information | |
| * I don't need. In a custom hypervisor, you'd just check the syndrome register | |
| * in your synchronous abort handler and then jump to your desired EL2 code. | |
| */ | |
| static int demo_trampoline_target(struct vcpu *v, mmio_info_t *not_important, | |
| register_t *ignore_me, void *ignore_me_too) | |
| { | |
| printk(XENLOG_G_ERR "Bounced up to EL2!\n"); | |
| vcpu_show_registers(v); | |
| return 1; | |
| } | |
| static struct mmio_handler_ops poc_mmio_ops = { | |
| .read = demo_trampoline_target, | |
| }; | |
| /** | |
| * Set up the hardware domain for the Tegra, giving it mediated access to the | |
| * platform's legacy interrupt controller. | |
| */ | |
| static int tegra_specific_mapping(struct domain *d) | |
| { | |
| int rc; | |
| unsigned long pfn_start, pfn_end; | |
| pfn_start = paddr_to_pfn(TEGRA_ICTLR_BASE); | |
| pfn_end = DIV_ROUND_UP(TEGRA_ICTLR_BASE + (TEGRA_ICTLR_SIZE * TEGRA_ICTLR_COUNT), PAGE_SIZE); | |
| /* XXX HAX FOR POC */ | |
| memory_trampoline_demo(d); | |
| /* Force all access to the ictlr to go through our mediators. */ | |
| rc = iomem_deny_access(d, pfn_start, pfn_end); | |
| if (rc) | |
| panic("Could not deny access to the Tegra LIC iomem!\n"); | |
| rc = unmap_mmio_regions(d, _gfn(pfn_start), pfn_end - pfn_start + 1, | |
| _mfn(pfn_start)); | |
| if (rc) | |
| panic("Could not deny access to the Tegra LIC!\n"); | |
| register_mmio_handler(d, &tegra_mmio_ops_ictlr, | |
| TEGRA_ICTLR_BASE, TEGRA_ICTLR_SIZE * TEGRA_ICTLR_COUNT, NULL); | |
| return 0; | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * linux kernel module | |
| */ | |
| #include <linux/fs.h> | |
| #include <linux/mm.h> | |
| #include <linux/init.h> | |
| #include <linux/module.h> | |
| #include <linux/miscdevice.h> | |
| #include <asm/io.h> | |
| #include <asm/uaccess.h> | |
| static int map_in_bounce(struct file *filp, struct vm_area_struct *vma) | |
| { | |
| /* You'd want to check permissions/sanity here, blah blah etc. */ | |
| int rc = remap_pfn_range(vma, vma->vm_start, 0x12345UL, PAGE_SIZE, vma->vm_page_prot); | |
| printk(KERN_WARNING "Remap result %d.\n", rc); | |
| return rc; | |
| } | |
| static struct file_operations bounce_fops = { | |
| .owner = THIS_MODULE, | |
| .mmap = map_in_bounce | |
| }; | |
| static struct miscdevice bounce_device = { | |
| MISC_DYNAMIC_MINOR, "bounce", &bounce_fops | |
| }; | |
| void __init trap_to_el2(void) | |
| { | |
| volatile int target; | |
| int * bounce = (int *)ioremap(0x12345000UL, PAGE_SIZE); | |
| printk(KERN_WARNING "Prodding buffer from EL1...\n"); | |
| target = *bounce; | |
| iounmap(bounce); | |
| } | |
| int __init init_example(void) | |
| { | |
| /* First, demo using the trampoline from EL1: */ | |
| trap_to_el2(); | |
| /* And then set up our bounce device. */ | |
| misc_register(&bounce_device); | |
| return 0; | |
| } | |
| void __exit exit_example(void) | |
| { | |
| /* Tear down our bounce device. */ | |
| misc_deregister(&bounce_device); | |
| } | |
| module_init(init_example); | |
| module_exit(exit_example); | |
| MODULE_LICENSE("GPL"); | |
| MODULE_DESCRIPTION("PoC for EL0->EL2 without EL1"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Prodding buffer from EL0... | |
| (XEN) Bounced up to EL2! | |
| (XEN) ----[ Xen-4.8-unstable arm64 debug=y Not tainted ]---- | |
| (XEN) CPU: 2 | |
| (XEN) PC: 00000000004007d0 | |
| (XEN) LR: 00000000004008b0 | |
| (XEN) SP_EL0: 0000007fe8471030 | |
| (XEN) SP_EL1: ffffffc035dbbff0 | |
| (XEN) CPSR: 60000000 MODE:64-bit EL0t (Guest User) | |
| (XEN) X0: 00000000deadbeef X1: 00000000cafebabe X2: 00000000badcafe5 | |
| (XEN) X3: 000000005afec0de X4: 00000079012e8000 X5: 00000000deadbeef | |
| (XEN) X6: 00000000cafebabe X7: 00000000badcafe5 X8: 000000005afec0de | |
| (XEN) X9: 00000079012e8000 X10: 0101010101010101 X11: 0000000000000038 | |
| (XEN) X12: 0000000000000000 X13: 000000790116c910 X14: 00000079012ebc70 | |
| (XEN) X15: 000000790115e098 X16: 0000000000000000 X17: 0000000000410cd8 | |
| (XEN) X18: 0000000000040600 X19: 00000000004008e0 X20: 0000000000000000 | |
| (XEN) X21: 0000000000000000 X22: 0000000000000000 X23: 0000000000000000 | |
| (XEN) X24: 0000000000000000 X25: 0000000000000000 X26: 0000000000000000 | |
| (XEN) X27: 0000000000000000 X28: 0000000000000000 FP: 0000007fe8471060 | |
| (XEN) | |
| (XEN) ELR_EL1: 0000007901216cd8 | |
| (XEN) ESR_EL1: 56000000 | |
| (XEN) FAR_EL1: 0000007958d73654 | |
| (XEN) | |
| (XEN) SCTLR_EL1: 34d5d91d | |
| (XEN) TCR_EL1: 34b5193519 | |
| (XEN) TTBR0_EL1: 031a0000b9a81000 | |
| (XEN) TTBR1_EL1: 00000000a1033000 | |
| (XEN) | |
| (XEN) VTCR_EL2: 80043594 | |
| (XEN) VTTBR_EL2: 000100017ff62000 | |
| (XEN) | |
| (XEN) SCTLR_EL2: 30cd183d | |
| (XEN) HCR_EL2: 000000008038663f | |
| (XEN) TTBR0_EL2: 000000017fefe000 | |
| (XEN) | |
| (XEN) ESR_EL2: 93c58005 | |
| (XEN) HPFAR_EL2: 0000000000123450 | |
| (XEN) FAR_EL2: 00000079012e8000 | |
| (XEN) | |
| And back at EL0! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <sys/mman.h> | |
| #include <sys/stat.h> | |
| #include <fcntl.h> | |
| #include <errno.h> | |
| #include <stdint.h> | |
| void try_bounce(int *bounce, uint64_t a, uint64_t b, uint64_t c, uint64_t d) | |
| { | |
| /* This isn't special, it just makes it clear what the registers are | |
| * when we call bounce. */ | |
| asm volatile( | |
| "mov x0, %0\n\t" | |
| "mov x1, %1\n\t" | |
| "mov x2, %2\n\t" | |
| "mov x3, %3\n\t" | |
| "mov x4, %4\n\t" | |
| "ldr x5, [x4]\n\t" | |
| : | |
| : "r" (a), "r" (b), "r" (c), "r" (d), "r" (bounce) | |
| : "r0", "r1", "r2", "r3", "r4" | |
| ); | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| int fd; | |
| int *bounce; | |
| fd = open("/dev/bounce", O_RDONLY); | |
| if(fd < 0) | |
| { | |
| printf("Whoops, couldn't open. Are you root?\n"); | |
| return -1; | |
| } | |
| printf("Opened %d.\n", fd); | |
| /* Get our handle on the trampoline pages. */ | |
| bounce = mmap(NULL, 4096, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0); | |
| if(bounce == MAP_FAILED) { | |
| printf("Whoops, couldn't map (%d).\n", errno); | |
| return -1; | |
| } | |
| printf("Prodding buffer from EL0...\n"); | |
| try_bounce(bounce, 0xDEADBEEF, 0xCAFEBABE, 0xBADCAFE5, 0x5AFEC0DE); | |
| printf("And back at EL0!\n"); | |
| munmap(bounce, 4096); | |
| close(fd); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment